﻿using Developer.Core.FrameWork.MicroClients.Attributes;
using Microsoft.Extensions.DependencyModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.Loader;
using System.Text;

namespace Developer.Core.FrameWork.HelpFile
{
    /// <summary>
    /// 程序集操作类
    /// </summary>
    public class AssemblyUntil
    {
        /// <summary>
        /// 获取项目下的所有程序集，不包括系统程序集，以及Nuget下的内容
        /// </summary>
        /// <returns></returns>
        public static IList<Assembly> GetAllAssemblies()
        {
            List<Assembly> listAssembly = new List<Assembly>();

            var deps = DependencyContext.Default;

            // 排除系统程序集以及Nuget下载包
            var libs = deps.CompileLibraries.Where(x => !x.Serviceable && x.Type != "package");

            foreach (var lib in libs)
            {
                try
                {
                    var assembly = AssemblyLoadContext.Default.LoadFromAssemblyName(new AssemblyName(lib.Name));
                    listAssembly.Add(assembly);
                }
                catch (Exception ex)
                {

                    throw;
                }
            }

            return listAssembly;
        }

        /// <summary>
        /// 获取单个程序集
        /// </summary>
        /// <param name="AssemblyName"></param>
        /// <returns></returns>
        public static Assembly GetAssembly(string AssemblyName) => GetAllAssemblies().FirstOrDefault(x => x.FullName.Contains(AssemblyName));

        /// <summary>
        /// 获取所有类型
        /// </summary>
        /// <returns></returns>
        public static IList<Type> GetAllTypes()
        {
            List<Type> list = new List<Type>();
            foreach (var assembly in GetAllAssemblies())
            {
                var typeInfos = assembly.DefinedTypes;
                foreach (var typeInfo in typeInfos)
                {
                    list.Add(typeInfo.AsType());
                }
            }
            return list;
        }

        /// <summary>
        /// 根据程序集名称获取类型
        /// </summary>
        /// <param name="assemblyName"></param>
        /// <returns></returns>
        public static IList<Type> GetTypesByAssembly(string assemblyName)
        {
            List<Type> list = new List<Type>();
            var assembly = AssemblyLoadContext.Default.LoadFromAssemblyName(new AssemblyName(assemblyName));
            var typeInfos = assembly.DefinedTypes;
            foreach (var typeInfo in typeInfos)
            {
                list.Add(typeInfo.AsType());
            }
            return list;
        }

        /// <summary>
        /// 获取包含MicroClient特性的程序集
        /// </summary>
        /// <param name="AssemblyName"></param>
        /// <returns></returns>
        public static IList<Type> GetMicroClientTypesByAssembly(string AssemblyName)
        {
            List<Type> list = new List<Type>();
            var assembly = AssemblyLoadContext.Default.LoadFromAssemblyName(new AssemblyName(AssemblyName));

            var typeInfos = assembly.DefinedTypes;

            foreach (var typeInfo in typeInfos)
            {
                MicroClient microClient = typeInfo.GetCustomAttribute<MicroClient>();
                if (microClient != null)
                {
                    list.Add(typeInfo.AsType());
                }
            }

            return list;
        }

        /// <summary>
        /// 获取实现类类型
        /// </summary>
        /// <param name="TypeName"></param>
        /// <param name="BaseInterfaceType"></param>
        /// <returns></returns>
        public static Type GetImplementType(string TypeName, Type BaseInterfaceType)
        {
            return GetAllTypes().FirstOrDefault(t =>
            {
                if (t.Name == TypeName && t.GetTypeInfo().GetInterfaces().Any(b => b.Name == BaseInterfaceType.Name))
                {
                    var typeinfo = t.GetTypeInfo();
                    return typeinfo.IsClass && !typeinfo.IsAbstract && !typeinfo.IsGenericType;
                }
                return false;
            });
        }
    }
}
